# Copyright 2024 Henrique Paone
#
# This file is part of Kitty-Tui.
#
# Kitty-Tui is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
# 
# Kitty-Tui is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along with
# Kitty-Tui. If not, see <https://www.gnu.org/licenses/>.

require_relative './tables.rb'

module Kitty
  # Note: The order of these two constants are important for the translate_bits
  # function. Do not change it
  Modifiers = [ 'A', '', 'T', 'C', 'A', 'S']
  Kitty_flags = {
    :associated_text => 16,
    :all_escaped => 8,
    :alternate_keys => 4,
    :event_types => 2,
    :disambiguate_escape_codes => 1
  }
  
  Kitty_builtin_regex = /\x1b\]133;[ABC]\x1b\\/

  # Fetch and parse KITTY_PIPE_DATA set by kitty
  def get_kitty_data
    kitty_data = /(\d+):(\d+,?\d+):(\d+,?\d+)/.match ENV['KITTY_PIPE_DATA']
    scrolled = kitty_data[1].to_i
    cline, ccol = kitty_data[2].split(',').reverse.map! do |e| e.to_i end
    lines, cols = kitty_data[3].split(',').map! do |e| e.to_i end
    { scrolled: scrolled, cline: cline, ccol: ccol, lines: lines, cols: cols }
  end
  
  def hi_line(line, cstart, cend, color)
    printf "\e[2*x\e[%d;%d;%d;%d;48;5;#{ color }$r\e[*x", line, cstart, line, cend, color
  end
  
  def unscroll(amt)
    print "\e[#{ amt }+T"
  end
  
  def translate_bits(num, reference_array)
    translation = []
    bits = num.bit_length
    reference = reference_array.last(bits).reverse
    bits.downto 0 do |i|
      translation <<  reference[i] if num[i] == 1
    end
    translation
  end
  
  def kitty_query_keyboard_flags
    print "\e[?u"
    flags = translate_bits(get_escaped.first[1..-1].to_i, Kitty_flags.values)
    enabled = []
    Kitty_flags.each_pair do |k, v|
      enabled << k if flags.include?(v)
    end
    enabled
  end
  

  def kitty_keyboard_enable(*options)
    flags = []
    options.each do |opts|
      flags << Kitty_flags[opts ]if Kitty_flags.include? opts
    end
    print "\e[>#{ flags.sum }u"
  end

  def kitty_restore
    print "\e[<u"
  end
  
  # gets an escaped sequence terminated in either u or ~. this is specially
  # useful for getting input when using the flag disambiguate_escape_codes
  def get_escaped
    is_arrow = false
    escaped = ''
    loop do
      c = STDIN.getch
      break if ['u', '~'].include? c
      escaped += c
      if ('A'..'D').include? c
        is_arrow = true
        break 
      end
    end
    has_mod = escaped.count(';') >= 1
    escaped = 
    if is_arrow and has_mod
      escaped[(escaped.index(';') + 1..-1)].insert 1, ';'
    else escaped[2..-1]
    end.split ';'
    if is_arrow and has_mod
      escaped[0] = escaped[0].to_i 
      escaped.reverse!
    end
    escaped
  end

  # This converts an escaped sequence using vi-like notation, for example, if
  # the user press ctrl+t, the function outputs <C-t>. Note that this requires
  # the disambiguate_escape_codes flag to be set in kitty
  def parse_escaped(escaped)
    ignore_shift = is_letter = false
    codepoint, mods, assoc_codep = escaped
    mods = mods.to_i - 1

    return nil if Ignore.include? codepoint
    
    key = if Functional_keys.include? codepoint
      Functional_keys[codepoint]
    else
      is_letter = true
      if codepoint == assoc_codep or assoc_codep.nil?
        '' << codepoint.to_i
      else
        ignore_shift = true
        '' << assoc_codep.to_i
      end
    end

    modifiers = []
    unless mods < 1
      modifiers = translate_bits(mods, Modifiers)
      modifiers.delete 'S' if ignore_shift
    end
    
    if modifiers.empty? 
      is_letter ? key : "<#{ key }>"
    else
      "<#{ modifiers.join '-' }-#{ key }>"
    end
  end
end
